package com.zlzlib.adb;

import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.TimeZone;

/**
 * adb命令库
 *
 * @DateTime: 2023/5/15 16:55
 * @Author zlz
 * @Version 1.0
 */
public class AdbCmd {

//    public static void main(String[] args) {
//        System.out.println(connect("172.2.3.3", 5555));
//        System.out.println(disconnectAll());
//        System.out.println(reboot("172.2.3.3"));
//    }

    /**
     * adb程序的地址
     */
    private static String adbHome = "";
    /**
     * 在不同环境这个字段不同
     */
    private static String findKey = "findStr";

    private static final String ADB = "adb";

    /**
     * 设置adb安装目录 如果设置了环境变量可以设置为空
     *
     * @param adbHome 地址
     */
    public static void setAdbHome(String adbHome) {
        AdbCmd.adbHome = adbHome;
    }

    private static String toCmd(String cmd) {
        return adbHome + cmd;
    }

    public static void useFindStr() {
        findKey = "findStr";
    }

    public static void useGrep() {
        findKey = "grep";
    }

    /**
     * 获得任意执行的adb命令
     *
     * @param ip  设备ip
     * @param cmd 命令
     * @return 完整命令
     */
    public static String getAdbCmd(String ip, String cmd) {
        return toCmd(String.format("%s -s %s %s", ADB, ip, cmd));
    }

    /**
     * 连接设备
     *
     * @param ip   地址
     * @param port 端口
     * @return 结果
     */
    public static String connect(String ip, int port) {
        return toCmd(String.format("%s connect %s:%s", ADB, ip, port));
    }

    /**
     * 断开设备
     *
     * @param ip 地址
     * @return 结果
     */
    public static String disconnect(String ip) {
        return toCmd(String.format("%s disconnect %s", ADB, ip));
    }

    /**
     * 断开全部设备
     *
     * @return 结果
     */
    public static String disconnectAll() {
        return disconnect("");
    }

    /**
     * 重启设备
     *
     * @param ip 地址
     * @return 结果
     */
    public static String reboot(String ip) {
        return getAdbCmd(ip, "reboot");
    }

    /**
     * 关闭设备
     *
     * @param ip 地址
     * @return 结果
     */
    public static String closeDevice(String ip) {
        return getAdbCmd(ip, "shell reboot -p");
    }

    /**
     * 安装apk
     *
     * @param ip       地址
     * @param apkPath  安装的apk文件地址  同一目录下可以用相对地址
     * @param isUpdate 是否更新
     * @return 结果
     */
    public static String installApk(String ip, String apkPath, boolean isUpdate) {
        if (isUpdate) {
            return getAdbCmd(ip, String.format("install -r %s", apkPath));
        } else {
            return getAdbCmd(ip, String.format("install  %s", apkPath));
        }
    }

    /**
     * 卸载apk
     *
     * @param ip          地址
     * @param packageName apk包名
     * @return 结果
     */
    public static String uninstallApk(String ip, String packageName) {
        return getAdbCmd(ip, String.format("shell pm uninstall %s", packageName));
    }

    /**
     * 强制关闭apk
     *
     * @param ip          地址
     * @param packageName apk包名
     * @return 结果
     */
    public static String closeApk(String ip, String packageName) {
        return getAdbCmd(ip, String.format("shell am force-stop %s", packageName));
    }

    /**
     * 打开apk的页面
     *
     * @param ip          地址
     * @param packageName 包名
     * @param openPage    页面包内全路径
     * @return 结果
     */
    public static String openApk(String ip, String packageName, String openPage) {
        return getAdbCmd(ip, String.format("shell am start %s/%s", packageName, openPage));
    }

    /**
     * 后台启动服务
     *
     * @param ip          地址
     * @param packageName 包名
     * @param openPage    服务全路径
     * @return 结果
     */
    public static String openService(String ip, String packageName, String openPage) {
        return getAdbCmd(ip, String.format("shell am startservice -n %s/%s", packageName, openPage));
    }

    public static String openServiceForeground(String ip, String packageName, String openPage) {
        return getAdbCmd(ip, String.format("shell am start-foreground-service -n %s/%s", packageName, openPage));
    }


    /**
     * 获取apk版本
     *
     * @param ip          地址
     * @param packageName 包名
     * @return 结果 versionName=xxxxx
     */
    public static String findApkVersionName(String ip, String packageName) {
        return getAdbCmd(ip, String.format("shell dumpsys package %s | %s versionName", packageName, findKey));
    }

    /**
     * 获取设备当前顶部apk 包名和页面
     *
     * @param ip 地址
     * @return 结果 mFocusedWindow=Window{41ba2440 u0 包名/当前顶部页面路径}
     */
    public static String findTopWindowApk(String ip) {
        return getAdbCmd(ip, String.format("shell dumpsys window | %s mFocusedWindow", findKey));
    }

    /**
     * 获得设备系统版本 名称
     *
     * @param ip 地址
     * @return 结果 4.4.4
     */
    public static String findDeviceVersionName(String ip) {
        return getAdbCmd(ip, "shell getprop ro.build.version.release");
    }

    /**
     * 获得设备系统版本 号码
     *
     * @param ip 地址
     * @return 结果 数字版本 19
     */
    public static String findDeviceVersionCode(String ip) {
        return getAdbCmd(ip, "shell getprop ro.build.version.sdk");
    }

    /**
     * 获取设备型号
     *
     * @param ip 地址
     * @return 结果 XBHV811
     */
    public static String findDeviceModel(String ip) {
        return getAdbCmd(ip, "shell getprop ro.product.model");
    }

    /**
     * 获取设备厂商名称
     *
     * @param ip 地址
     * @return 结果 XBHV811
     */
    public static String findDeviceBrand(String ip) {
        return getAdbCmd(ip, "shell getprop ro.product.brand");
    }

    /**
     * 获取设备物理密度 dpi
     *
     * @param ip 地址
     * @return 结果 Physical density: 160
     * 如果和原始不一样
     * Physical density: 160
     * Override density: 240
     */
    public static String findDeviceDensity(String ip) {
        return getAdbCmd(ip, "shell wm density");
    }

    /**
     * 设置设备物理密度 dpi
     *
     * @param ip 地址
     * @return 结果
     */
    public static String setDeviceDensity(String ip, int value) {
        return getAdbCmd(ip, String.format("shell wm density %s", value));
    }

    /**
     * 获取设备分辨率
     *
     * @param ip 地址
     * @return 结果 Physical size: 1920x1080
     */
    public static String findDeviceSize(String ip) {
        return getAdbCmd(ip, "shell wm size");
    }

    /**
     * 获取亮度是否为自动调节
     *
     * @param ip 地址
     * @return 结果 0：未开启  1：开启
     */
    public static String findDeviceBrightnessMode(String ip) {
        return getAdbCmd(ip, "shell settings get system screen_brightness_mode");
    }

    /**
     * 获取当前屏幕亮度值
     *
     * @param ip 地址
     * @return 结果 0-255
     */
    public static String findDeviceBrightnessValue(String ip) {
        return getAdbCmd(ip, "shell settings get system screen_brightness");
    }

    /**
     * 设置屏幕亮度
     *
     * @param ip    地址
     * @param value 亮度 0-255  超过255反而不是最亮
     * @return 结果 为空成功
     */
    public static String setDeviceBrightnessValue(String ip, int value) {
        return getAdbCmd(ip, String.format("shell settings put system screen_brightness %s", value));
    }

    /**
     * 代理设备端口
     *
     * @param ip         地址
     * @param pcPort     代理之后pc的端口
     * @param devicePort 代理的设备端口
     * @return 结果 成功返回 pcPort
     */
    public static String forwardDevice(String ip, int pcPort, int devicePort) {
        return getAdbCmd(ip, String.format("forward tcp:%s tcp:%s", pcPort, devicePort));
    }

    /**
     * 移除pc代理的端口
     *
     * @param ip     设备ip
     * @param pcPort 电脑代理端口
     * @return 成功返回为空
     */
    public static String forwardRemovePort(String ip, int pcPort) {
        return getAdbCmd(ip, String.format("forward --remove tcp:%s", pcPort));
    }

    /**
     * 移除所有代理的端口
     *
     * @param ip 设备ip
     * @return 成功返回为空
     */
    public static String forwardRemoveAllPort(String ip) {
        return getAdbCmd(ip, "forward --remove -all");
    }

    /**
     * 查看文件是否存在
     *
     * @param ip       地址
     * @param filePath 文件地址
     * @return 结果 包含No such file or directory为不存在
     */
    public static String fileIsExit(String ip, String filePath) {
        return getAdbCmd(ip, String.format("shell ls %s", filePath));
    }

    /**
     * 执行apk里面的java main程序
     *
     * @param ip       地址
     * @param apkPath  apk地址
     * @param mainPath main程序在apk里面的地址
     * @param args     main的参数
     * @return 结果
     */
    public static String exeApkJavaMain(String ip, String apkPath, String mainPath, String... args) {
        StringBuilder tmp = new StringBuilder(String.format
                ("shell export CLASSPATH=%s;exec app_process /system/bin %s", apkPath, mainPath));
        for (String arg : args) {
            tmp.append(" ").append(arg);
        }
        return getAdbCmd(ip, tmp.toString());
    }

    /**
     * 获得通过声音服务设置的命令
     * <p>
     * 4.4.2（19）  = 7  15  17
     * 4.4.3-4.4.4 （20） = 8  16  18
     * 5.0-5.1  （21-22）= 4  13  15
     * 6.0 （23） = 3  9  11
     * 7.0 -7.1 （24-25） = 3   8  10
     *
     * @param ip     地址
     * @param line   方法行数  不同版本不同
     * @param type   类型
     * @param volume 音量
     * @return 声音命令
     */
    private static String getServiceSetAudio(String ip, int line, int type, int volume) {
        return getAdbCmd(ip, String.format("shell service call audio %s i32 %s i32 %s i32 0", line, type, volume));
    }

    private static String getServiceGetAudio(String ip, int line, int type) {
        return getAdbCmd(ip, String.format("shell service call audio %s i32 %s", line, type));
    }

    /**
     * Result: Parcel(00000000    '....')
     * <p>
     * [v] will control stream=3 (STREAM_MUSIC)
     * [v] will set volume to index=0
     * [v] Connecting to AudioService
     * java.lang.SecurityException:
     *
     * @param ip      地址
     * @param version 系统版本
     * @param type    声音类型
     * @param volume  音量
     * @return 26以上和26以下格式不同
     */
    public static String setAudio(String ip, int version, int type, int volume) {
        String cmd;
        if (version >= 26) {
            cmd = getAdbCmd(ip, String.format("shell media volume --show --stream %s --set %s", type, volume));
        } else if (version == 24 || version == 25 || version == 23) {
            //7.0-7.1 6.0
            cmd = getServiceSetAudio(ip, 3, type, volume);
        } else if (version == 21 || version == 22) {
            //5.0-5.1
            cmd = getServiceSetAudio(ip, 4, type, volume);
        } else if (version == 20) {
            //4.4.3 - 4.4.4
            cmd = getServiceSetAudio(ip, 8, type, volume);
        } else {
            //Android 4.4 - 4.4.2
            cmd = getServiceSetAudio(ip, 7, type, volume);
        }
        return cmd;
    }

    /**
     * [v] will control stream=3 (STREAM_MUSIC)
     * [v] will get volume
     * [v] Connecting to AudioService
     * [v] volume is 0 in range [0..100]
     * <p>
     * Result: Parcel(00000000 00000005   '........')
     *
     * @param ip      地址
     * @param version 系统版本
     * @param type    声音类型
     * @return 26以上和26以下格式不同
     */
    public static String getCurrentAudio(String ip, int version, int type) {
        String cmd;
        if (version >= 26) {
            cmd = getAdbCmd(ip, String.format("shell media volume --show --stream %s --get", type));
        } else if (version == 24 || version == 25) {
            //7.0-7.1
            cmd = getServiceGetAudio(ip, 8, type);
        } else if (version == 23) {
            //6.0
            cmd = getServiceGetAudio(ip, 9, type);
        } else if (version == 21 || version == 22) {
            //5.0-5.1
            cmd = getServiceGetAudio(ip, 13, type);
        } else if (version == 20) {
            //4.4.3 - 4.4.4
            cmd = getServiceGetAudio(ip, 16, type);
        } else {
            //Android 4.4.2
            cmd = getServiceGetAudio(ip, 15, type);
        }
        return cmd;
    }

    /**
     * [v] will control stream=3 (STREAM_MUSIC)
     * [v] will get volume
     * [v] Connecting to AudioService
     * [v] volume is 0 in range [0..100]
     * <p>
     * Parcel(00000000 0000000f   '........')
     *
     * @param ip      地址
     * @param version 系统版本
     * @param type    声音类型
     * @return 26以上和26以下格式不同
     */
    public static String getMaxAudio(String ip, int version, int type) {
        String cmd;
        if (version >= 26) {
            cmd = getCurrentAudio(ip, version, type);
        } else if (version == 24 || version == 25) {
            //7.0-7.1
            cmd = getServiceGetAudio(ip, 10, type);
        } else if (version == 23) {
            //6.0
            cmd = getServiceGetAudio(ip, 11, type);
        } else if (version == 21 || version == 22) {
            //5.0-5.1
            cmd = getServiceGetAudio(ip, 15, type);
        } else if (version == 20) {
            //4.4.3 - 4.4.4
            cmd = getServiceGetAudio(ip, 18, type);
        } else {
            //Android 4.4.2
            cmd = getServiceGetAudio(ip, 17, type);
        }
        return cmd;
    }

    /**
     * 输入按键
     *
     * @param ip    设备ip
     * @param event 按键指令
     * @return 返回为空
     */
    public static String inputKeyEvent(String ip, AdbKeyEvent event) {
        return getAdbCmd(ip, String.format("shell input keyevent %s", event.getValue()));
    }

    /**
     * 设置时间
     *
     * @param ip      设备ip
     * @param version 版本
     * @param time    时间戳
     * @return Thu Jun  1 15:56:00 CST 2023
     */
    public static String setSystemTime(String ip, int version, long time) {
        String cmd;
        if (version >= 23) {
            cmd = String.format("shell date %s", getMyDateFormat("MMddHHmmyyyy.ss").format(time));
        } else {
            cmd = String.format("shell date -s %s", getMyDateFormat("yyyyMMdd.HHmmss").format(time));
        }
        return getAdbCmd(ip, cmd);
    }

    /**
     * 获得时间
     *
     * @param ip 设备ip
     * @return Thu Jun  1 15:56:00 CST 2023
     */
    public static String getSystemTime(String ip) {
        return getAdbCmd(ip, "shell date");
    }

    public static SimpleDateFormat getMyDateFormat(String format) {
        SimpleDateFormat df = new SimpleDateFormat(format, Locale.getDefault());
        //设置时区为中国时区
        df.setTimeZone(TimeZone.getTimeZone("GMT+08:00"));
        return df;
    }

    /**
     * 获得三方安装包列表
     *
     * @param ip  设备ip
     * @param key 筛选的名称
     * @return package:xxx  package:xxx
     */
    public static String getOtherPackages(String ip, String key) {
        return getAdbCmd(ip, "shell pm list packages -3 " + key);
    }

    /**
     * 获得当前包名的安装包位置信息
     *
     * @param ip   设备ip
     * @param name 包名
     * @return package:安装包文件地址=包名
     */
    public static String getPackagePath(String ip, String name) {
        return getAdbCmd(ip, "shell pm list packages -f " + name);
    }

    /**
     * 获得日期命令
     * @param ip 设备ip
     * @param key 过滤字段
     * @return 一个执行的进程
     */
    public static String getLogcat(String ip,String key){
        if(key==null||key.isEmpty()){
            return getAdbCmd(ip, "logcat");
        }
        return getAdbCmd(ip, "logcat -s "+key);
    }
}
